package hdgeom.primitives;

import java.util.ArrayList;

import processing.core.PVector;
import simpleMesh.Face;

public class Plane {
	public PVector origin;
	public PVector normal;
	public Plane(PVector o, PVector n){
		origin=o;
		normal=n;
	}
	public Plane(float x,float y,float z,float nx,float ny,float nz){
		origin=new PVector(x,y,z);
		normal=new PVector(nx,ny,nz);
		normal.normalize();
	}
	public Plane(PVector p1, PVector p2, PVector p3) {
		origin = p1;
		PVector v = PVector.sub(p3, p2);
		PVector u = PVector.sub(p2, p1);
		normal = new PVector();
		PVector.cross(v, u, normal);
		normal.normalize();
	}
	public Plane(float x1,float y1,float z1,float x2,float y2,float z2,float x3,float y3,float z3) {
		this(new PVector(x1,y1,z1),new PVector(x2,y2,z2),new PVector(x3,y3,z3));
	}
	public PVector segmentPlaneIntersection(PVector s1, PVector s2) {
		PVector u = PVector.sub(s2, s1);
		PVector w = PVector.sub(s1, origin);
		float d = PVector.dot(normal, u);
		float n = -PVector.dot(normal, w);
		if (Math.abs(d) < 0.0000001) // segment is parallel to plane
			return null;
		float t = n / d;
		if (t < 0 || t > 1)
			return null; // no intersection with Segment
		return new PVector(s1.x + t * u.x, s1.y + t * u.y, s1.z + t * u.z);
	}
	public PVector linePlaneIntersection(float x,float y,float z,float dx,float dy,float dz) {
		return linePlaneIntersection(new PVector(x,y,z),new PVector(dx,dy,dz));
	}
	public PVector linePlaneIntersection(PVector s1, PVector u) {
		PVector w = PVector.sub(s1, origin);
		float d = PVector.dot(normal, u);
		float n = -PVector.dot(normal, w);
		if (Math.abs(d) < 0.0000001) // segment is parallel to plane
			return null;
		float t = n / d;
		
		return new PVector(s1.x + t * u.x, s1.y + t * u.y, s1.z + t * u.z);
	}

	// splits a face with a line defined by a and b
	// if we split a convex face (like rectangle, no concave corners), there
	// should be max 2 intersections
	// if there are two intersections we make 2 new faces.
	// otherwise there is no intersection and we return the original face
	public ArrayList<Face> splitConvexFace(Face face) {
		int indexIntersect = 0;
		int nPts = face.vertices.size();
		PVector[] intersections = new PVector[2];
		int[] indexes = new int[2];
		for (int i = 0; i < nPts; i++) {
			PVector p1 = face.vertices.get(i);
			PVector p2 = face.vertices.get((i + 1) % nPts);
			PVector intersection = segmentPlaneIntersection(p1, p2);
			if (intersection != null) {
				intersections[indexIntersect] = intersection;
				indexes[indexIntersect] = (i + 1) % nPts;
				indexIntersect++;
			}
		}
		ArrayList<Face> newFaces = new ArrayList<Face>();
		if (indexIntersect == 2) {
			Face f1 = new Face();
			int cI = indexes[0];
			int end = indexes[1];
			f1.vertices.add(intersections[0]);
			while (cI != end) {
				f1.vertices.add(face.vertices.get(cI));
				cI++;
				cI = cI % nPts;
			}
			f1.vertices.add(intersections[1]);
			Face f2 = new Face();
			cI = indexes[1];
			end = indexes[0];
			f2.vertices.add(intersections[1]);
			while (cI != end) {
				f2.vertices.add(face.vertices.get(cI));
				cI++;
				cI = cI % nPts;
			}
			f2.vertices.add(intersections[0]);
			newFaces.add(f1);
			newFaces.add(f2);
		}
		else {
			newFaces.add(face);
		}
		return newFaces;
	}
	public ArrayList<Face> splitConvexFaces(ArrayList<Face> faces) {
		ArrayList<Face> newFaces=new ArrayList<Face>();
		for (int i=0;i<faces.size();i++){
			newFaces.addAll(splitConvexFace(faces.get(i)));
		}
		return newFaces;
	}
	public float getDistance(float x,float y,float z){
		float d0=-normal.dot(origin);
		return d0+normal.dot(x,y,z);
	}
	public float getDistance(PVector v){
		return getDistance(v.x,v.y,v.z);
	}
}
